exports.Command = new Class(/** @lends CaboCity.cmd.Command# */{
	/**
	 * @class Crea un nuevo commando para poder ser configurado.
	 * @constructs
	 * 
	 * @property {CaboCity.cmd.FOutsideTODO} input Acommand call from an extern client
	 * @property {CaboCity.cmd.FInsideTODO} output A command call from inside server.
	 * @property {String} name A string identificating the command.
	 * @property {Integer} id The identification o the command.
	 * 
	 * @param {Integer} id
	 * @param {String} name
	 * 
	 * */
	initialize: function(id, name){
		this.id = id;
		this.name = name;
	}
	
	/**
	 * Establece el comando a ejecutar en una llamada externa.
	 * @public
	 * */
	,setFOutside: function(output){
		this.output = output;
	}
	
	/**
	 * Establece el comando a ejecutar en una llamada interna del servidor.
	 * */
	,setFInside: function(){
		
	}
	
	/**
	 * Ejecuta el comando outside.
	 * 
	 * @param {CaboCity.Client} client El objeto cliente al que va ligado el comando.
	 * @param {{}} arg Argumentos requeridos por ese comando.
	 * 
	 * @return CaboCity.Answer
	 * */
	,executeOutside: function(client, arg){
		this.output();
	}
	
	/**
	 * Check if the command is configured correctly.
	 * @public
	 * @return Boolean
	 * */
	,isGoodFormed: function(){
		
	}
});

exports.Answer = new Class(/** @lends CaboCity.cmd.Answer */{
	/**
	 * @class Crea una respuesta.
	 * @constructs
	 * 
	 * @property {Object} data Información almacenada para ser enviada como respuesta.
	 * 
	 * */
	initialize: function(){
		
	}
	
	/**
	 * Establece a quien se envía la respuesta y la información que se requiera almacenar en la misma para ser enviada.
	 * @public
	 * @param {CaboCity.Client} client Cliente receptor de la respuesta.
	 * @param {{client: CaboCity.Client , data: Object{}}[]} data Información para almacenar.
	 * */
	,setReceiver: function(client, data){
		
	}
	
	/**
	 * Envia la respuesta.
	 * @public
	 * @param {CaboCity.Client} client Cliente por defecto para enviar la información por defecto.
	 * */
	,send: function(client){
		
	}
});

exports.iniExt = function(main){
	main.addExt({
		ini: function(){
			this.commands = {}; //[idcommand]
			this.commandPending = {}; //[iduser][idcommand]
		}
		
		/*
		Add new command to the command list.
		commandDef have the form: {
			r : COMMANDID, //request
			fun: COMMANDFUN(command) //if the command is an output command :: needs confirmation, but not data.
			,answerFun: COMMANDANSWERFUN(command) //if the command is an input command.
		}
		*/
		,addNewCommand: function(commandDef){
			if( !this.checkCommand(commandDef.r) ){
				this.commands[commandDef.r] = {
					fun : (commandDef.fun) ? commandDef.fun : this.makeAnswer
					,answerFun: commandDef.answerFun
				};
			} else {
				console.log("Error adding new command. Command duplicated.");
			}
		}
	
		//Check if a command is into command list.
		,checkCommand: function(request){
			if( request && this.commands[request] ) return true;
			else return false;
		}
	
		/*All command object have the form:
			c : {
				r : COMMANDID, //request
				idc: IDCOMMAND
				, (....)
			}
		*/
		,executeCommandForClient: function(client, command){
			if( this.checkCommand(command.r) )
				var answer = this.commands[command.r].fun.bind(this, client, command)();
			else
				var answer = this.makeAnswer(command);
			return answer;
		}
		,processAnswerForClient: function(client, answer){
			var cp = this.clients[client.id].commandPending[answer.idc];
			if( cp ) {
				this.commands[cp.r].answerFun.bind(this, client, answer.answer)();
				delete this.clients[client.id].commandPending[answer.idc];
			} else
				console.log("Respuesta desconocida.");
		}
		,makeAndSendCommand: function(request, args){
			var l = Object.getLength(this.clients[client.id].commandPending);
			var command = {r: request, idc: l, 'args': args};
			this.clients[client.id].commandPending[l] = command; //Save the command in pending commands for an answer.
		
			this.sendCommand(command);
		}
		
		//return a valid answer object. If answer is false or null it is considered a failed answer.
		,makeAnswer: function(command, answer){
			if(!answer) return {idc: command.idc , 'answer' : 'fail'};
			else return {idc: command.idc , 'answer' : answer};
		}
		,sendAnswer: function(client, answer){
			this.clients[client.id].socket.emit('answer', answer);
		}
		,sendCommand: function(client, command){
			this.clients[client.id].socket.emit('command', command);
		}
	});
}
